import {AxiosRequestConfig, AxiosResponse, AxiosInstance} from 'axios';
import {Result} from '@/base/Result';
import ViewUI from 'view-design';
import {deepAssign} from '@/base/util/Objects';
import {Page} from '@/base/Page';
import {isEmpty} from "@/base/util/Strings";

export class RestClient {
  constructor(instance: AxiosInstance) {
    this.instance = instance;
  }

  instance: AxiosInstance;

  /**
   * 支持获取基础类型值, 如String, Number, Boolean
   */
  get<T>(Clazz: { new(): T }, url: string, config?: AxiosRequestConfig): Promise<Result<T>> {
    const that = this;
    // @ts-ignore
    ViewUI.LoadingBar.start();
    return new Promise<Result<T>>(function (resolve, reject) {
      // console.log(that.instance.get(url, config))
      that.instance.get(url, config).then((res: AxiosResponse) => {
        // @ts-ignore
        ViewUI.LoadingBar.finish();
        if (res.data.name) {
          // @ts-ignore
          resolve(new Result<T>(res.data.name, res.data.message, null));
        } else {
          let data = new Clazz();
          if (data instanceof String || data instanceof Number || data instanceof Boolean) {
            data = res.data.data;
          } else {
            // @ts-ignore
            if (data.parse !== undefined) {
              // @ts-ignore
              data.parse(res.data.data);
            } else {
              deepAssign(data, res.data.data);
            }
          }
          const result = new Result<T>(res.data.name, res.data.message, data);
          resolve(result);
        }
      }).catch((reason: any) => {
        // @ts-ignore
        ViewUI.LoadingBar.finish();
        reject(reason);
      });
    });
  }
  getDomain<T>(Clazz: { new(): T }, url: string, config?: AxiosRequestConfig): Promise<Result<T>> {
    const that = this;
    // @ts-ignore
    ViewUI.LoadingBar.start();
    return new Promise<Result<T>>(function (resolve, reject) {
      that.instance.get(url, config).then((res: AxiosResponse) => {
        // @ts-ignore
        ViewUI.LoadingBar.finish();
        if (res.data.name) {
          // @ts-ignore
          resolve(new Result<>(res.data.name, res.data.message, null));
        } else {
          const result = new Result<T>(res.data.name, res.data.message, res.data.data);
          resolve(result);
        }
      }).catch((reason: any) => {
        // @ts-ignore
        ViewUI.LoadingBar.finish();
        reject(reason);
      });
    });
  }

  getArray<T>(Clazz: { new(): T }, url: string, config?: AxiosRequestConfig): Promise<Result<Array<T>>> {
    const that = this;
    // @ts-ignore
    ViewUI.LoadingBar.start();
    // console.log(that.instance.get(url, config));
    return new Promise<Result<Array<T>>>(function (resolve, reject) {
      that.instance.get(url, config).then((res: AxiosResponse) => {
        // @ts-ignore
        ViewUI.LoadingBar.finish();
        if (res.data.name) {
          // @ts-ignore
          resolve(new Result<T>(res.data.name, res.data.message, null));
        } else {
          const array = res.data.data.map(item => {
            let data = new Clazz();
            if (data instanceof String || data instanceof Number || data instanceof Boolean) {
              data = item;
            } else {
              // @ts-ignore
              if (data.parse !== undefined) {
                // @ts-ignore
                data.parse(item);
              } else {
                deepAssign(data, item);
              }
            }
            return data;
          });
          const result = new Result<Array<T>>(res.data.name, res.data.message, array);
          resolve(result);
        }
      }).catch((reason: any) => {
        // @ts-ignore
        ViewUI.LoadingBar.finish();
        reject(reason);
      });
    });
  }

  getPage<T>(Clazz: { new(): T }, url: string, config?: AxiosRequestConfig): Promise<Result<Page<T>>> {
    const that = this;
    // @ts-ignore
    ViewUI.LoadingBar.start();
    return new Promise<Result<Page<T>>>(function (resolve, reject) {
      // console.log(that.instance.get(url, config));
      that.instance.get(url, config).then((res: AxiosResponse) => {
        // @ts-ignore
        ViewUI.LoadingBar.finish();
        if (res.data.name) {
          // @ts-ignore
          resolve(new Result<T>(res.data.name, res.data.message, null));
        } else {
          const items = res.data.data.items.map(item => {
            let data = new Clazz();
            if (data instanceof String || data instanceof Number || data instanceof Boolean) {
              data = item;
            } else {
              // @ts-ignore
              if (data.parse !== undefined) {
                // @ts-ignore
                data.parse(item);
              } else {
                deepAssign(data, item);
              }
            }
            return data;
          });
          const pageCount: number = res.data.data.pageCount;
          const pageIndex: number = res.data.data.pageIndex;
          const pageSize: number = res.data.data.pageSize;
          const itemCount: number = res.data.data.itemCount;
          const extras: Array<any> = res.data.data.extras == null ? [] : res.data.data.extras;
          const page = new Page<T>(items, pageCount, pageIndex, pageSize, itemCount, extras);
          const result = new Result<Page<T>>(res.data.name, res.data.message, page);
          resolve(result);
        }
      }).catch((reason: any) => {
        // @ts-ignore
        ViewUI.LoadingBar.finish();
        reject(reason);
      });
    });
  }
  getProcutModelData<T>(Clazz: { new(): T }, url: string, config?: AxiosRequestConfig): Promise<Result<Page<T>>> {
    const that = this;
    // @ts-ignore
    ViewUI.LoadingBar.start();
    return new Promise<Result<Page<T>>>(function (resolve, reject) {
      // console.log(that.instance.get(url, config));
      that.instance.get(url, config).then((res: AxiosResponse) => {
        // @ts-ignore
        ViewUI.LoadingBar.finish();
        if (isEmpty(res.data.data)) {
          res.data.name = 'notfound';
        }
        if (res.data.name) {
          // @ts-ignore
          resolve(new Result<T>(res.data.name, res.data.message, null));
        } else {
          const items = res.data.data.map(item => {
            let data = new Clazz();
            if (data instanceof String || data instanceof Number || data instanceof Boolean) {
              data = item;
            } else {
              // @ts-ignore
              if (data.parse !== undefined) {
                // @ts-ignore
                data.parse(item);
              } else {
                deepAssign(data, item);
              }
            }
            return data;
          });
          // const pageCount: number = res.data.data.pageCount;
          // const pageIndex: number = res.data.data.pageIndex;
          // const pageSize: number = res.data.data.pageSize;
          // const itemCount: number = res.data.data.itemCount;
          // const extras: Array<any> = res.data.data.extras == null ? [] : res.data.data.extras;
          // const page = new Page<T>(items, pageCount, pageIndex, pageSize, itemCount, extras);
          const result = new Result<Page<T>>(res.data.name, res.data.message, items);
          resolve(result);
        }
      }).catch((reason: any) => {
        // @ts-ignore
        ViewUI.LoadingBar.finish();
        reject(reason);
      });
    });
  }

  getData<T>(Clazz: { new(): T }, url: string, config?: AxiosRequestConfig): Promise<Result<Page<T>>> {
    const that = this;
    // @ts-ignore
    ViewUI.LoadingBar.start();
    return new Promise<Result<Page<T>>>(function (resolve, reject) {
      that.instance.get(url, config).then((res: AxiosResponse) => {
        // @ts-ignore
        ViewUI.LoadingBar.finish();
        if (res.data.name) {
          // @ts-ignore
          resolve(new Result<T>(res.data.name, res.data.message, null));
        } else {
          const items = res.data.data.map(item => {
            let data = new Clazz();
            if (data instanceof String || data instanceof Number || data instanceof Boolean) {
              data = item;
            } else {
              // @ts-ignore
              if (data.parse !== undefined) {
                // @ts-ignore
                data.parse(item);
              } else {
                deepAssign(data, item);
              }
            }
            return data;
          });
          // const pageCount: number = res.data.data.pageCount;
          // const pageIndex: number = res.data.data.pageIndex;
          // const pageSize: number = res.data.data.pageSize;
          // const itemCount: number = res.data.data.itemCount;
          // const extras: Array<any> = res.data.data.extras == null ? [] : res.data.data.extras;
          // const page = new Page<T>(items, pageCount, pageIndex, pageSize, itemCount, extras);
          const result = new Result<Page<T>>(res.data.name, res.data.message, items);
          resolve(result);
        }
      }).catch((reason: any) => {
        // @ts-ignore
        ViewUI.LoadingBar.finish();
        reject(reason);
      });
    });
  }

  delete(url: string, config?: AxiosRequestConfig): Promise<Result<void>> {
    const that = this;
    // @ts-ignore
    ViewUI.LoadingBar.start();
    return new Promise<Result<any>>(function (resolve, reject) {
      that.instance.delete(url, config).then((res: AxiosResponse) => {
        // @ts-ignore
        ViewUI.LoadingBar.finish();
        if (res.data.name) {
          // @ts-ignore
          resolve(new Result<T>(res.data.name, res.data.message, null));
        } else {
          const result = new Result<any>(res.data.name, res.data.message, null);
          resolve(result);
        }
      }).catch((reason: any) => {
        // @ts-ignore
        ViewUI.LoadingBar.finish();
        reject(reason);
      });
    });
  }

  post<T>(Clazz: { new(): T }, url: string, data?: any, config?: AxiosRequestConfig): Promise<Result<T>> {
    const that = this;
    // @ts-ignore
    ViewUI.LoadingBar.start();
    return new Promise<Result<T>>(function (resolve, reject) {
      // console.log(that.instance.put(url, data, config));
      that.instance.post(url, data, config).then((res: AxiosResponse) => {
        // @ts-ignore
        ViewUI.LoadingBar.finish();
        if (res.data.name && res.data.name !== '0') {
          // @ts-ignore
          resolve(new Result<T>(res.data.name, res.data.message, null));
        } else {
          let data = new Clazz();
          if (data instanceof String || data instanceof Number || data instanceof Boolean) {
            data = res.data.data;
          } else {
            // @ts-ignore
            if (data.parse !== undefined) {
              // @ts-ignore
              data.parse(res.data.data);
            } else {
              deepAssign(data, res.data.data);
            }
          }
          const result = new Result<T>(res.data.name, res.data.message, data);
          resolve(result);
        }
      }).catch((reason: any) => {
        // @ts-ignore
        ViewUI.LoadingBar.finish();
        reject(reason);
      });
    });
  }

  put<T>(Clazz: { new(): T }, url: string, data?: any, config?: AxiosRequestConfig): Promise<Result<T>> {
    const that = this;
    // @ts-ignore
    ViewUI.LoadingBar.start();
    return new Promise<Result<T>>(function (resolve, reject) {
      that.instance.put(url, data, config).then((res: AxiosResponse) => {
        // @ts-ignore
        ViewUI.LoadingBar.finish();
        if (res.data.name) {
          // @ts-ignore
          resolve(new Result<T>(res.data.name, res.data.message, null));
        } else {
          let data = new Clazz();
          if (data instanceof String || data instanceof Number || data instanceof Boolean) {
            data = res.data.data;
          } else {
            // @ts-ignore
            if (data.parse !== undefined) {
              // @ts-ignore
              data.parse(res.data.data);
            } else {
              if (res.data.data !== undefined) {
                data = res.data.data
              } else {
                deepAssign(data, res.data);
              }
            }
          }
          const result = new Result<T>(res.data.name, res.data.message, data);
          resolve(result);
        }
      }).catch((reason: any) => {
        // @ts-ignore
        ViewUI.LoadingBar.finish();
        reject(reason);
      });
    });
  }

  patch<T>(Clazz: { new(): T }, url: string, data?: any, config?: AxiosRequestConfig): Promise<Result<T>> {
    const that = this;
    // @ts-ignore
    ViewUI.LoadingBar.start();
    return new Promise<Result<T>>(function (resolve, reject) {
      that.instance.patch(url, data, config).then((res: AxiosResponse) => {
        // @ts-ignore
        ViewUI.LoadingBar.finish();
        if (res.data.name) {
          // @ts-ignore
          resolve(new Result<T>(res.data.name, res.data.message, null));
        } else {
          let data = new Clazz();
          if (data instanceof String || data instanceof Number || data instanceof Boolean) {
            data = res.data.data;
          } else {
            // @ts-ignore
            if (data.parse !== undefined) {
              // @ts-ignore
              data.parse(res.data.data);
            } else {
              deepAssign(data, res.data.data);
            }
          }
          const result = new Result<T>(res.data.name, res.data.message, data);
          resolve(result);
        }
      }).catch((reason: any) => {
        // @ts-ignore
        ViewUI.LoadingBar.finish();
        reject(reason);
      });
    });
  }
}
